//////////////////////////////////////////////////
// EASIM project
// easim.draw.Painter
// 6/7/2007 4:26 PM
// Cong Liu
// gzcong@gmail.com

// Copyright (C) 2007
// All rights reserved.
// Refer to LICENSE of JIST (Java In Simulation Time) for terms and conditions of use.

package easim.draw;

import java.awt.Graphics;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;

public class Painter implements jist.runtime.JistAPI.DoNotRewrite
{

	public static void paint(Graphics graphics, Field field) {
		graphics.setColor(Color.WHITE);
		graphics.fillRect(0, 0, field.width, field.height);
    Iterator it = field.links.keySet().iterator();
    while (it.hasNext()) {
		  String link = (String)it.next();
			String[] nodes = link.split("-");
			paint(graphics, (Link)field.links.get(link), 
        (Node)field.nodes.get(nodes[0]), (Node)field.nodes.get(nodes[1]));
		}
		Node[] nodes = (Node[])field.nodes.values().toArray(new Node[0]);
		sortNodes(nodes);
		for (int i = 0; i < nodes.length; ++ i) {
			paint(graphics, nodes[i], null);
		}
		graphics.setColor(Color.BLACK);
		graphics.drawRect(0, 0, field.width - 1, field.height - 1);
	}

	public static void paint(Graphics graphics, Link link, Node node1, Node node2) {
		graphics.setColor(Setting.LineStyle.getValue(link.lineStyle).getColor());
		int dx = node1.x - node2.x;
		int dy = node1.y - node2.y;
    if (dx < 0) dx = -dx;
    if (dy < 0) dy = -dy;
		double length = Math.sqrt(dx * dx + dy * dy);
    if (dx > dy) {
      int x1 = node1.x;
      int y1 = node1.y - link.thickness / 2;
      int x2 = node2.x;
      int y2 = node2.y - link.thickness / 2;
      for (int i = 0; i < link.thickness; ++ i) {
			  graphics.drawLine(x1, y1 + i, x2, y2 + i);
      }
    }
    else {
      int x1 = node1.x - link.thickness / 2;
      int y1 = node1.y;
      int x2 = node2.x - link.thickness / 2;
      int y2 = node2.y;
      for (int i = 0; i < link.thickness; ++ i) {
			  graphics.drawLine(x1 + i, y1, x2 + i, y2);
      }
    }
    if (! (length > node1.size + node1.thickness + node2.size + node2.thickness)) return;
    dx = node1.x - node2.x;
    dy = node1.y - node2.y;
    int x1 = node1.x - (int)(dx * (node1.size + node1.thickness) / length);
    int y1 = node1.y - (int)(dy * (node1.size + node1.thickness) / length);
    int x2 = node2.x + (int)(dx * (node2.size + node2.thickness) / length);
    int y2 = node2.y + (int)(dy * (node2.size + node2.thickness) / length);
    if (link.arrow.equals("ARROW1") || link.arrow.equals("ARROW_BOTH")) {
      graphics.drawOval(x2-3, y2-3, 6, 6);
    }
    if (link.arrow.equals("ARROW2") || link.arrow.equals("ARROW_BOTH")) {
      graphics.drawOval(x1-3, y1-3, 6, 6);
    }
		if (link.label != null && link.label.trim().length() != 0) {
			int fontSize = node1.size * 3 / 2;
			if (fontSize > node2.size * 3 / 2) fontSize = node2.size * 3 / 2;
      if (fontSize > 15) fontSize = 15;
			Font font = new Font(Setting.FONT, Font.PLAIN, fontSize);
			graphics.setFont(font);
			FontMetrics fontMetrics = graphics.getFontMetrics(font);
      String[] text = link.label.split("\\\\n");
      int width = 0;
      int height = fontSize * text.length;
      for (int i = 0; i < text.length; ++ i) {
        int w = fontMetrics.stringWidth(text[i]);
        if (width < w) width = w;
      }
      dx = x1 - x2;
      dy = y1 - y2;
      if (dx == 0 && dy == 0) return;
      int x = (x1 + x2) / 2;
      int y = (y1 + y2) / 2;
      int gap = link.thickness / 2 + 1;
      double len = Math.sqrt(width * width + height * height) / 2;
      double len2 = Math.sqrt(dx * dx + dy * dy);
      len += gap;
      if (dx == 0) {
        if (dy > 0) {
          x += width / 2 + gap;
        }
        else {
          x -= width / 2 + gap;
        }
      }
      else if (dy == 0) {
        if (dx > 0) {
          y -= height / 2 + gap;
        }
        else {
          y += height / 2 + gap;
        }
      }
      else {
        if (dx > 0 && dy > 0) {
          double tan1 = - dx / (double)dy;
          double tan2 = - height / (double)width;
          double tan12 = (tan1 - tan2)/(1 + tan1 * tan2);
          double alpha = Math.atan(tan12);
          double dis = len * Math.cos(alpha);
          x += (int)(dis * (dy / len2));
          y -= (int)(dis * (dx / len2));
        }
        else if (dx > 0 && dy < 0) {
          double tan1 = - dx / (double)dy;
          double tan2 = height / (double)width;
          double tan12 = (tan1 - tan2)/(1 + tan1 * tan2);
          double alpha = Math.atan(tan12);
          double dis = len * Math.cos(alpha);
          x -= (int)(dis * (-dy / len2));
          y -= (int)(dis * (dx / len2));
        }
        else if (dx < 0 && dy < 0) {
          double tan1 = - dx / (double)dy;
          double tan2 = - height / (double)width;
          double tan12 = (tan1 - tan2)/(1 + tan1 * tan2);
          double alpha = Math.atan(tan12);
          double dis = len * Math.cos(alpha);
          x += (int)(dis * (dy / len2));
          y -= (int)(dis * (dx / len2));
        }
        else if (dx < 0 && dy > 0) {
          double tan1 = - dx / (double)dy;
          double tan2 = height / (double)width;
          double tan12 = (tan1 - tan2)/(1 + tan1 * tan2);
          double alpha = Math.atan(tan12);
          double dis = len * Math.cos(alpha);
          x += (int)(dis * (dy / len2));
          y += (int)(dis * (-dx / len2));
        }
      }
      x = x - width / 2;
      y = y - height / 2 - (int)(fontSize * 0.22);
      for (int i = 0; i < text.length; ++ i) {
        graphics.drawString(text[i], x, y + (i + 1) * fontSize);
      }
      /*
      int gap = link.thickness / 2;
			int fx = (node1.x + node2.x) / 2 + 2 + gap;
			int fy = (node1.y + node2.y) / 2 - 2 - gap;
			if (node1.y >= node2.y) fx -= fontWidth + 4 + link.thickness;
			if (node1.x > node2.x) fy += fontSize + link.thickness;
			graphics.drawString(link.label, fx, fy);
      /**/
		}
  }

	public static void paint(Graphics graphics, Node node, Color color) {
		int size2 = node.size + node.thickness - 1;
		graphics.setColor(Color.WHITE);
		graphics.fillOval(node.x - size2, node.y - size2, size2 * 2, size2 * 2);
		if (color == null) {
			color = Setting.LineStyle.getValue(node.lineStyle).getColor();
		}
		graphics.setColor(color);
		int size = node.size;
		for (int i = 0; i < node.thickness; ++ i) {
			graphics.drawOval(node.x - size, node.y - size, size * 2, size * 2);
			++ size;
		}
		if (node.label != null && node.label.trim().length() != 0) {
      String[] text = node.label.split("\\\\n");
			int fontSize = node.size * 2 / text.length;
			while (fontSize >= 8) {
				Font font = new Font(Setting.FONT, Font.PLAIN, fontSize);
				FontMetrics fontMetrics = graphics.getFontMetrics(font);
				int fontWidth = 0;
        for (int i = 0; i < text.length; ++ i) {
          int width = fontMetrics.stringWidth(text[i]);
          if (width > fontWidth) fontWidth = width;
        }
        int width = fontWidth;
        int height = fontSize * text.length;
				if (width * width + height * height > node.size * node.size * 4) {
          double times = (width * width + height * height) / (double)(node.size * node.size * 4);
          times = Math.sqrt(times);
					int newSize = (int)(fontSize / times);
          if (newSize < fontSize) {
            fontSize = newSize;
          }
          else {
            -- fontSize;
          }
					continue;
				}
				graphics.setFont(font);
        int x = node.x - width / 2;
        int y = node.y - height / 2 - (int)(fontSize * 0.22);
        for (int i = 0; i < text.length; ++ i) {
          graphics.drawString(text[i], x, y + (i + 1) * fontSize);
        }
				break;
			}
		}
	}

	public static void paint(Graphics graphics, String text, int fontSize, int x, int y, int mode) {
		String[] lines = text.split("\n");
		Font font = new Font(Setting.FONT, Font.PLAIN, fontSize);
		FontMetrics fontMetrics = graphics.getFontMetrics(font);
		int maxFontWidth = 0;
		for (int i = 0; i < lines.length; ++ i) {
			int fontWidth = fontMetrics.stringWidth(lines[i]);
			if (maxFontWidth < fontWidth) maxFontWidth = fontWidth;
		}
    if ((mode & 1) == 1) {
      x -= maxFontWidth;
    }
    if ((mode & 2) == 0) {
		  y -= fontSize * lines.length;
    }
		graphics.setColor(Color.WHITE);
		graphics.fillRect(x - 3, y - 3, maxFontWidth + 4, fontSize * lines.length + 6);
		graphics.setColor(Color.BLACK);
		graphics.setFont(font);
		for (int i = 0; i < lines.length; ++ i) {
			int y2 = y + fontSize * (i + 1);
			graphics.drawString(lines[i], x, y2);
		}
    if ((mode & 4) == 4) {
      graphics.drawRect(x - 3, y - 3, maxFontWidth + 4, fontSize * lines.length + 6);
    }
  }

  static class Comparator1 implements Comparator, jist.runtime.JistAPI.DoNotRewrite
  {
    public int compare(Object node01, Object node02) {
      Node node1 = (Node)node01;
      Node node2 = (Node)node02;
      return node1.id.compareTo(node2.id);
    }
  }

	public static void sortNodes(Node[] nodes) {
		Arrays.sort(nodes, new Comparator1());
	}

}

